"""
带外管理服务
提供带外管理的CRUD操作和业务逻辑
"""

import logging
import uuid
from datetime import datetime
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func

try:
    from src.app.database.models import OobManagement, Asset, IpManagement
    from src.app.database.database import get_database_manager
    from src.app.modules.oob.cache import OobCache
    from src.app.modules.oob.utils import OobUtils
except ImportError:
    # 尝试相对导入
    try:
        from ...database.models import OobManagement, Asset, IpManagement
        from ...database.database import get_database_manager
        from .cache import OobCache
        from .utils import OobUtils
    except ImportError as e:
        logger.error(f"导入带外管理服务依赖失败: {e}")
        raise

logger = logging.getLogger(__name__)

class OobService:
    """带外管理服务类"""
    
    def __init__(self):
        self.db_manager = get_database_manager()
        self.cache = OobCache()
        self.utils = OobUtils()
        self.logger = logging.getLogger(__name__)
    
    def create_oob(self, oob_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        创建带外管理
        
        Args:
            oob_data: 带外管理数据
            
        Returns:
            创建结果
        """
        # 验证数据
        is_valid, error_msg = self.utils.validate_oob_data(oob_data)
        if not is_valid:
            return {'success': False, 'message': error_msg}
        
        # 格式化数据
        oob_data = self.utils.format_oob_data(oob_data)
        
        # 验证设备资产是否存在
        with self.db_manager.get_session() as session:
            asset = session.query(Asset).filter(
                Asset.asset_id == oob_data['asset_id']
            ).first()
            
            if not asset:
                return {'success': False, 'message': f"设备资产 {oob_data['asset_id']} 不存在"}
            
            # 检查设备是否已有带外管理
            existing_oob = session.query(OobManagement).filter(
                OobManagement.asset_id == oob_data['asset_id']
            ).first()
            
            if existing_oob:
                return {'success': False, 'message': f"设备资产 {oob_data['asset_id']} 已存在带外管理"}
            
            # 创建带外管理
            try:
                oob = OobManagement(
                    oob_id=oob_data['oob_id'],
                    asset_id=oob_data['asset_id'],
                    login_url=oob_data['login_url']
                )
                
                session.add(oob)
                session.commit()
                
                # 清除缓存
                self.cache.invalidate_list_cache()
                self.cache.invalidate_statistics_cache()
                
                self.logger.info(f"创建带外管理成功: {oob.oob_id}")
                return {
                    'success': True, 
                    'message': '带外管理创建成功',
                    'data': {
                        'oob_id': oob.oob_id,
                        'asset_id': oob.asset_id,
                        'login_url': oob.login_url,
                        'create_time': oob.create_time.isoformat() if oob.create_time else None
                    }
                }
                
            except Exception as e:
                session.rollback()
                self.logger.error(f"创建带外管理失败: {str(e)}")
                return {'success': False, 'message': f"创建带外管理失败: {str(e)}"}
    
    def update_oob(self, oob_id: str, oob_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        更新带外管理
        
        Args:
            oob_id: 带外管理ID
            oob_data: 更新数据
            
        Returns:
            更新结果
        """
        # 验证数据
        is_valid, error_msg = self.utils.validate_oob_data(oob_data)
        if not is_valid:
            return {'success': False, 'message': error_msg}
        
        # 格式化数据
        oob_data = self.utils.format_oob_data(oob_data)
        
        with self.db_manager.get_session() as session:
            # 查找带外管理
            oob = session.query(OobManagement).filter(
                OobManagement.oob_id == oob_id
            ).first()
            
            if not oob:
                return {'success': False, 'message': f"带外管理 {oob_id} 不存在"}
            
            # 如果更换了设备资产，验证新设备是否存在
            if oob_data['asset_id'] != oob.asset_id:
                asset = session.query(Asset).filter(
                    Asset.asset_id == oob_data['asset_id']
                ).first()
                
                if not asset:
                    return {'success': False, 'message': f"设备资产 {oob_data['asset_id']} 不存在"}
                
                # 检查新设备是否已有带外管理
                existing_oob = session.query(OobManagement).filter(
                    and_(
                        OobManagement.asset_id == oob_data['asset_id'],
                        OobManagement.oob_id != oob_id
                    )
                ).first()
                
                if existing_oob:
                    return {'success': False, 'message': f"设备资产 {oob_data['asset_id']} 已存在带外管理"}
            
            try:
                # 更新信息
                oob.asset_id = oob_data['asset_id']
                oob.login_url = oob_data['login_url']
                oob.update_time = datetime.now()
                
                session.commit()
                
                # 清除缓存
                self.cache.invalidate_oob_cache(oob_id)
                self.cache.invalidate_list_cache()
                self.cache.invalidate_statistics_cache()
                
                self.logger.info(f"更新带外管理成功: {oob_id}")
                return {
                    'success': True, 
                    'message': '带外管理更新成功',
                    'data': {
                        'oob_id': oob.oob_id,
                        'asset_id': oob.asset_id,
                        'login_url': oob.login_url,
                        'update_time': oob.update_time.isoformat() if oob.update_time else None
                    }
                }
                
            except Exception as e:
                session.rollback()
                self.logger.error(f"更新带外管理失败: {str(e)}")
                return {'success': False, 'message': f"更新带外管理失败: {str(e)}"}
    
    def delete_oob(self, oob_id: str) -> Dict[str, Any]:
        """
        删除带外管理
        
        Args:
            oob_id: 带外管理ID
            
        Returns:
            删除结果
        """
        with self.db_manager.get_session() as session:
            # 查找带外管理
            oob = session.query(OobManagement).filter(
                OobManagement.oob_id == oob_id
            ).first()
            
            if not oob:
                return {'success': False, 'message': f"带外管理 {oob_id} 不存在"}
            
            # 检查是否有IP地址绑定到此带外管理
            ip_count = session.query(IpManagement).filter(
                IpManagement.oob_id == oob_id
            ).count()
            
            if ip_count > 0:
                return {'success': False, 'message': f"带外管理 {oob_id} 下还有 {ip_count} 个IP地址，无法删除"}
            
            try:
                # 删除带外管理
                session.delete(oob)
                session.commit()
                
                # 清除缓存
                self.cache.invalidate_oob_cache(oob_id)
                self.cache.invalidate_list_cache()
                self.cache.invalidate_statistics_cache()
                
                self.logger.info(f"删除带外管理成功: {oob_id}")
                return {'success': True, 'message': '带外管理删除成功'}
                
            except Exception as e:
                session.rollback()
                self.logger.error(f"删除带外管理失败: {str(e)}")
                return {'success': False, 'message': f"删除带外管理失败: {str(e)}"}
    
    def get_oob_by_id(self, oob_id: str) -> Dict[str, Any]:
        """
        根据ID获取带外管理信息
        
        Args:
            oob_id: 带外管理ID
            
        Returns:
            带外管理信息
        """
        # 先从缓存获取
        cached_data = self.cache.get_oob_by_id(oob_id)
        if cached_data:
            return cached_data
        
        with self.db_manager.get_session() as session:
            # 查询带外管理
            oob = session.query(OobManagement).filter(
                OobManagement.oob_id == oob_id
            ).first()
            
            if not oob:
                return {'success': False, 'message': f"带外管理 {oob_id} 不存在"}
            
            # 获取关联的设备资产信息
            asset = session.query(Asset).filter(
                Asset.asset_id == oob.asset_id
            ).first()
            
            # 获取关联的IP地址数量
            ip_count = session.query(IpManagement).filter(
                IpManagement.oob_id == oob_id
            ).count()
            
            # 构建返回数据
            oob_data = {
                'oob_id': oob.oob_id,
                'asset_id': oob.asset_id,
                'login_url': oob.login_url,
                'create_time': oob.create_time.isoformat() if oob.create_time else None,
                'update_time': oob.update_time.isoformat() if oob.update_time else None,
                'asset_name': asset.asset_name if asset else None,
                'asset_type': asset.asset_type if asset else None,
                'ip_count': ip_count
            }
            
            # 缓存数据
            self.cache.set_oob_by_id(oob_id, oob_data)
            
            return {'success': True, 'data': oob_data}
    
    def get_oob_list(self, page: int = 1, page_size: int = 50, 
                    filter_type: str = None, filter_value: str = None,
                    search_text: str = None) -> Dict[str, Any]:
        """
        获取带外管理列表
        
        Args:
            page: 页码
            page_size: 每页大小
            filter_type: 筛选类型
            filter_value: 筛选值
            search_text: 搜索文本
            
        Returns:
            带外管理列表
        """
        # 先从缓存获取完整列表
        cached_list = self.cache.get_oob_list()
        
        if not cached_list:
            with self.db_manager.get_session() as session:
                # 查询带外管理列表
                query = session.query(OobManagement, Asset).join(
                    Asset, OobManagement.asset_id == Asset.asset_id
                )
                
                # 执行查询
                results = query.all()
                
                # 构建数据列表
                cached_list = []
                for oob, asset in results:
                    # 获取IP地址数量
                    ip_count = session.query(IpManagement).filter(
                        IpManagement.oob_id == oob.oob_id
                    ).count()
                    
                    oob_data = {
                        'oob_id': oob.oob_id,
                        'asset_id': oob.asset_id,
                        'login_url': oob.login_url,
                        'create_time': oob.create_time.isoformat() if oob.create_time else None,
                        'update_time': oob.update_time.isoformat() if oob.update_time else None,
                        'asset_name': asset.asset_name if asset else None,
                        'asset_type': asset.asset_type if asset else None,
                        'ip_count': ip_count
                    }
                    cached_list.append(oob_data)
                
                # 缓存列表
                self.cache.set_oob_list(cached_list)
        
        # 应用筛选
        filtered_list = cached_list.copy()
        
        if filter_type and filter_value:
            filtered_list = self.utils.filter_oob_data(filtered_list, filter_type, filter_value)
        
        if search_text:
            filtered_list = self.utils.search_oob_data(filtered_list, search_text)
        
        # 分页处理
        total_count = len(filtered_list)
        start_index = (page - 1) * page_size
        end_index = start_index + page_size
        page_data = filtered_list[start_index:end_index]
        
        return {
            'success': True,
            'data': page_data,
            'pagination': {
                'page': page,
                'page_size': page_size,
                'total_count': total_count,
                'total_pages': (total_count + page_size - 1) // page_size
            }
        }
    
    def get_statistics(self) -> Dict[str, Any]:
        """
        获取统计信息
        
        Returns:
            统计信息
        """
        # 先从缓存获取
        cached_stats = self.cache.get_statistics()
        if cached_stats:
            return cached_stats
        
        with self.db_manager.get_session() as session:
            # 总数统计
            total_count = session.query(OobManagement).count()
            
            # 按带外类型统计
            type_stats = {}
            all_oobs = session.query(OobManagement).all()
            
            for oob in all_oobs:
                oob_type = self.utils.get_oob_type_from_url(oob.login_url)
                if oob_type not in type_stats:
                    type_stats[oob_type] = 0
                type_stats[oob_type] += 1
            
            # 按设备类型统计
            asset_type_stats = session.query(
                Asset.asset_type, 
                func.count(OobManagement.oob_id)
            ).join(
                OobManagement, Asset.asset_id == OobManagement.asset_id
            ).group_by(Asset.asset_type).all()
            
            asset_stats = {item[0]: item[1] for item in asset_type_stats}
            
            # IP绑定统计
            ip_binding_stats = session.query(
                func.count(OobManagement.oob_id)
            ).filter(
                OobManagement.oob_id.in_(
                    session.query(IpManagement.oob_id).filter(
                        IpManagement.oob_id.isnot(None)
                    ).distinct()
                )
            ).scalar()
            
            statistics = {
                'total_count': total_count,
                'type_distribution': type_stats,
                'asset_type_distribution': asset_stats,
                'ip_binding_count': ip_binding_stats or 0,
                'no_ip_binding_count': total_count - (ip_binding_stats or 0)
            }
            
            # 缓存统计信息
            self.cache.set_statistics(statistics)
            
            return statistics
    
    def get_asset_without_oob(self) -> List[Dict[str, Any]]:
        """
        获取没有带外管理的设备资产列表
        
        Returns:
            设备资产列表
        """
        with self.db_manager.get_session() as session:
            # 查询没有带外管理的设备
            subquery = session.query(OobManagement.asset_id).subquery()
            
            assets = session.query(Asset).filter(
                ~Asset.asset_id.in_(session.query(subquery.c.asset_id))
            ).all()
            
            asset_list = []
            for asset in assets:
                asset_list.append({
                'asset_id': asset.asset_id,
                'asset_name': asset.asset_name,
                'asset_type': asset.asset_type,
                'model': asset.model
            })
            
            return asset_list
    
    def batch_delete_oob(self, oob_ids: List[str]) -> Dict[str, Any]:
        """
        批量删除带外管理
        
        Args:
            oob_ids: 带外管理ID列表
            
        Returns:
            删除结果
        """
        if not oob_ids:
            return {'success': False, 'message': '请选择要删除的带外管理'}
        
        success_count = 0
        failed_count = 0
        error_messages = []
        
        with self.db_manager.get_session() as session:
            for oob_id in oob_ids:
                try:
                    # 查找带外管理
                    oob = session.query(OobManagement).filter(
                        OobManagement.oob_id == oob_id
                    ).first()
                    
                    if not oob:
                        failed_count += 1
                        error_messages.append(f"带外管理 {oob_id} 不存在")
                        continue
                    
                    # 检查是否有IP地址绑定
                    ip_count = session.query(IpManagement).filter(
                        IpManagement.oob_id == oob_id
                    ).count()
                    
                    if ip_count > 0:
                        failed_count += 1
                        error_messages.append(f"带外管理 {oob_id} 下还有 {ip_count} 个IP地址")
                        continue
                    
                    # 删除带外管理
                    session.delete(oob)
                    success_count += 1
                    
                    # 清除缓存
                    self.cache.invalidate_oob_cache(oob_id)
                    
                except Exception as e:
                    failed_count += 1
                    error_messages.append(f"删除带外管理 {oob_id} 失败: {str(e)}")
            
            try:
                session.commit()
                
                # 清除列表和统计缓存
                self.cache.invalidate_list_cache()
                self.cache.invalidate_statistics_cache()
                
                result_message = f"批量删除完成：成功 {success_count} 个，失败 {failed_count} 个"
                if error_messages:
                    result_message += f"。错误详情：{'; '.join(error_messages[:3])}"
                    if len(error_messages) > 3:
                        result_message += f" 等{len(error_messages)}个错误"
                
                self.logger.info(f"批量删除带外管理: {result_message}")
                return {
                    'success': True, 
                    'message': result_message,
                    'success_count': success_count,
                    'failed_count': failed_count
                }
                
            except Exception as e:
                session.rollback()
                self.logger.error(f"批量删除带外管理失败: {str(e)}")
                return {'success': False, 'message': f"批量删除失败: {str(e)}"}
    
    def export_oob_data(self, oob_ids: List[str] = None) -> List[Dict[str, Any]]:
        """
        导出带外管理数据
        
        Args:
            oob_ids: 带外管理ID列表，如果为None则导出全部
            
        Returns:
            导出的数据列表
        """
        with self.db_manager.get_session() as session:
            query = session.query(OobManagement, Asset).join(
                Asset, OobManagement.asset_id == Asset.asset_id
            )
            
            if oob_ids:
                query = query.filter(OobManagement.oob_id.in_(oob_ids))
            
            results = query.all()
            
            export_data = []
            for oob, asset in results:
                # 获取IP地址数量
                ip_count = session.query(IpManagement).filter(
                    IpManagement.oob_id == oob.oob_id
                ).count()
                
                export_item = {
                    '带外管理ID': oob.oob_id,
                    '设备资产ID': oob.asset_id,
                    '设备名称': asset.asset_name if asset else '',
                    '设备类型': asset.asset_type if asset else '',
                    '登录URL': oob.login_url,
                    '带外类型': self.utils.get_oob_type_from_url(oob.login_url),
                    'IP地址数量': ip_count,
                    '创建时间': oob.create_time.strftime('%Y-%m-%d %H:%M:%S') if oob.create_time else '',
                    '更新时间': oob.update_time.strftime('%Y-%m-%d %H:%M:%S') if oob.update_time else ''
                }
                export_data.append(export_item)
            
            return export_data